Skip to content

向量检索基础与原理

学习目标

  • 理解向量检索的核心概念和基本原理
  • 了解文本嵌入和向量表示的基础知识
  • 掌握向量相似度计算的主要方法
  • 熟悉常见的向量索引算法和搜索技术
  • 理解向量检索在AI应用中的重要作用

回顾RAG流程:

RAG Workflow ( Retrieval-Augmented Generation AI) | by Kushal Sharma |  Medium

其中关键的就是Vector DB,Embedding Model。

而我们这个部分重点介绍,向量数据库及向量检索。

什么是向量检索?

向量检索(Vector Search)是一种用于在大规模向量数据集中快速寻找相似项的技术。它将传统的关键词匹配搜索扩展到了语义层面,能够理解查询的潜在含义,而不仅仅是表面的词汇匹配。

向量检索的定义:在向量空间中,寻找与给定查询向量距离最近(或相似度最高)的一组向量的过程。

多义词语义理解示例:苹果与小米

当用户搜索"苹果"或"小米"这样的词时,系统需要理解用户真正的搜索意图:

  • 苹果可能指水果🍎,也可能指Apple公司或其产品📱
  • 小米可能指谷物🌾,也可能指小米科技公司及其产品

传统关键词搜索只能匹配含有"苹果"或"小米"的文档,无法理解上下文语义:

搜索"苹果"→ 同时返回水果资料和电子设备信息,混杂无序
搜索"小米手环"→ 可能找不到"米环"的相关资料(词汇不完全匹配)

向量检索通过语义理解解决这个问题:

python
# 向量表示示例
"苹果手机新款发布" → [0.2, 0.7, -0.1, ...] → 靠近电子产品语义空间
"苹果营养价值高"   → [0.8, -0.3, 0.2, ...] → 靠近水果语义空间
"小米手机性价比"   → [0.3, 0.6, -0.2, ...] → 靠近电子产品语义空间
"小米粥的做法"     → [0.7, -0.4, 0.1, ...] → 靠近食品语义空间

当用户搜索"想买新手机,苹果还是小米好?"时:

  1. 查询被转换为语义向量
  2. 系统自动识别这是关于手机的查询
  3. 返回苹果手机、小米手机的相关信息,而非水果或食品

甚至当用户搜索"苹果设备"时,系统能返回"iPhone"、"iPad"等相关结果,即使这些文档中没有"苹果"这个词。这展示了向量检索如何超越简单词汇匹配,提供真正的语义理解能力。

为什么需要向量检索?

在以下场景中,传统的关键词搜索往往表现不佳:

  1. 语义理解:用户查询"苹果手机",系统需要理解这是指设备而非水果
  2. 相似概念:查询"汽车"时,"轿车"、"轿跑车"等相关结果也应被检索
  3. 多语言搜索:用中文搜索,也能找到英文的相关内容
  4. 内容推荐:基于用户喜好推荐相似内容,而非简单的标签匹配
  5. 图像搜索:查找相似图像,而非仅依赖图像标签

向量检索通过捕捉数据的语义表示,可以很好地解决上述问题。

向量空间基础

什么是向量表示?

向量表示是将对象(如文本、图像、音频等)转换为固定维度的数值数组,以便在向量空间中进行数学运算。

例如,一个句子可以被表示为一个300维的向量:

"人工智能正在改变世界" → [0.2, -0.5, 0.1, ..., 0.7]

这个向量捕捉了句子的语义信息,使得语义相似的句子在向量空间中的位置也相近。

image-20250429164300284

embedding模型(嵌入模型、特征模型、语义模型等叫法):

image-20250429162928845

文本嵌入技术

文本嵌入(Text Embedding)是将文本转换为向量的过程,主要技术包括:

  1. Word2Vec:基于神经网络的词嵌入技术,学习词的分布式表示
  2. GloVe:结合全局矩阵分解和局部上下文窗口的词嵌入方法
  3. FastText:考虑子词信息的嵌入技术,适合处理形态丰富的语言
  4. BERT Embedding:从预训练语言模型中提取的上下文敏感嵌入
  5. Sentence-BERT:专为句子级嵌入优化的模型
  6. OpenAI Embedding:如text-embedding-ada-002等模型提供的高质量嵌入

嵌入模型示例

下面是使用不同嵌入模型的简单示例:

python
# 使用Sentence-BERT生成句子嵌入
from sentence_transformers import SentenceTransformer

model = SentenceTransformer('paraphrase-MiniLM-L6-v2')
sentences = [
    "这是一个关于人工智能的文章",
    "AI正在各个领域得到应用",
    "机器学习是人工智能的一个子领域"
]

# 生成嵌入
embeddings = model.encode(sentences)
print(f"嵌入维度: {embeddings.shape}")  # 例如: (3, 384)
python
# 使用OpenAI API生成嵌入
import openai

openai.api_key = "your-api-key"
response = openai.Embedding.create(
    model="text-embedding-ada-002",
    input="人工智能正在改变世界"
)
embedding = response['data'][0]['embedding']
print(f"嵌入维度: {len(embedding)}")  # 1536

向量相似度计算

向量检索的核心是计算向量之间的相似度(或距离)。常用的度量方法包括:

1. 余弦相似度(Cosine Similarity)

定义:测量两个向量夹角的余弦值,范围[-1, 1],值越大表示越相似。

公式

$$ \text{cos}(A, B) = \frac{\sum_{i=1}^{n} A_i B_i}{\sqrt{\sum_{i=1}^{n} A_i^2} \cdot \sqrt{\sum_{i=1}^{n} B_i^2}} $$ 特点

  • 只关注向量方向,忽略大小
  • 对于文本相似度比较常用
  • 计算简单,易于实现

Python实现

python
import numpy as np
from scipy.spatial.distance import cosine

def cosine_similarity(vec1, vec2):
    return 1 - cosine(vec1, vec2)  # scipy的cosine计算的是距离,需要用1减

# 示例
vec1 = np.array([0.2, 0.5, 0.8])
vec2 = np.array([0.1, 0.4, 0.9])
similarity = cosine_similarity(vec1, vec2)
print(f"余弦相似度: {similarity}")  
# 输出接近0.99
# 余弦相似度: 0.9846306294290864

2. 欧几里得距离(Euclidean Distance)

定义:两点在欧几里得空间中的直线距离。

公式: $$ d(A, B) = \sqrt{\sum_{i=1}^{n} (A_i - B_i)^2} $$ 特点

  • 考虑向量的绝对大小
  • 适合值域相似的特征
  • 距离越小表示越相似

Python实现

python
from scipy.spatial.distance import euclidean

def euclidean_similarity(vec1, vec2):
    # 转换为相似度,使用exp(-distance)或1/(1+distance)
    distance = euclidean(vec1, vec2)
    return 1 / (1 + distance)

# 示例
similarity = euclidean_similarity(vec1, vec2)
print(f"欧几里得相似度: {similarity}")
# 欧几里得相似度: 0.8523658961269199

3. 曼哈顿距离(Manhattan Distance)

定义:沿坐标轴方向的距离总和。

公式: $$ d(A, B) = \sum_{i=1}^{n} |A_i - B_i| $$

特点

  • 计算简单,对异常值不敏感
  • 在网格状空间中有物理意义

4. 点积(Dot Product)

定义:两个向量对应元素乘积的和。

公式: $$ A \cdot B = \sum_{i=1}^{n} A_i B_i $$ 特点

  • 计算非常高效
  • 对于归一化向量等价于余弦相似度

Python实现

python
def dot_product(vec1, vec2):
    return np.dot(vec1, vec2)

相似度计算方法比较

度量方法优点缺点适用场景
余弦相似度忽略向量大小,专注方向不考虑数值差异文本相似度,推荐系统
欧几里得距离直观,有几何意义计算量大,受维度影响低维空间中的聚类
曼哈顿距离计算快,对异常值不敏感仅适用于网格结构城市街区类问题
点积计算极其高效值域不固定归一化向量的相似度

在实际应用中,余弦相似度和点积(对归一化向量)是向量检索中最常用的相似度度量方法。

向量索引技术

当向量数量达到百万或更多时,暴力搜索(与每个向量计算相似度)变得不可行。向量索引技术通过构建特殊的数据结构,实现近似最近邻(ANN: Approximate Nearest Neighbor)搜索,大幅提高检索效率。

主要的向量索引算法

1. 树形结构

KD-Tree(K-Dimensional Tree)

  • 原理:将空间递归划分为子空间
  • 优点:对低维数据效果好
  • 缺点:高维数据(>20维)性能急剧下降

Ball Tree

  • 原理:基于超球体划分空间
  • 优点:在高维空间中比KD-Tree更有效
  • 缺点:构建成本高

2. 量化方法

PQ(Product Quantization)

  • 原理:将高维向量分解为低维子向量,然后量化
  • 优点:内存占用小,查询速度快
  • 缺点:精度有损失

SQ(Scalar Quantization)

  • 原理:对向量每个维度进行量化
  • 优点:实现简单
  • 缺点:精度损失较大

3. 基于图的方法

HNSW(Hierarchical Navigable Small World)

  • 原理:多层图结构,上层为下层的快速索引
  • 优点:检索速度极快,精度高
  • 缺点:内存占用大,不支持动态删除

NSG(Navigating Spreading-out Graph)

  • 原理:优化的图结构,减少冗余边
  • 优点:比HNSW内存效率更高
  • 缺点:构建复杂

4. 基于哈希的方法

LSH(Locality-Sensitive Hashing)

  • 原理:相似向量映射到相同的桶
  • 优点:内存效率高,适合超大规模数据
  • 缺点:召回率较低

向量索引库比较

索引库算法特点适用场景
FaissPQ, HNSW, IVF等高性能,适合GPU加速大规模、高维向量
Annoy随机投影树构建快,内存占用小静态数据集
NMSLIBHNSW, SW-graph查询速度最快需要高性能检索
ScaNNAH, ANNSGoogle开发,高精度大规模推荐系统
Milvus多种算法分布式,易扩展企业级向量数据库

实践: HNSW算法示例

HNSW (Hierarchical Navigable Small World) 是当前最流行的向量索引算法之一,以下是使用它的简单示例:

python
import numpy as np
import hnswlib

# 生成示例数据
dim = 128  # 向量维度
num_elements = 10000  # 向量数量

# 随机生成向量
data = np.random.random((num_elements, dim)).astype('float32')

# 初始化HNSW索引
index = hnswlib.Index(space='cosine', dim=dim)  # 可选space: cosine, l2, ip
index.init_index(max_elements=num_elements, ef_construction=200, M=16)

# 添加向量到索引
index.add_items(data)

# 设置搜索参数
index.set_ef(50)  # ef越大,搜索越精确但越慢

# 执行搜索
query_vector = np.random.random(dim).astype('float32')
labels, distances = index.knn_query(query_vector, k=5)

print("最相似的5个向量索引:", labels)
print("对应的相似度:", 1 - np.array(distances))  # 对于cosine space,转换为相似度

# 保存和加载索引
index.save_index("hnsw_index.bin")
loaded_index = hnswlib.Index(space='cosine', dim=dim)
loaded_index.load_index("hnsw_index.bin", max_elements=num_elements)

向量检索与大语言模型

向量检索在大语言模型(LLM)应用中扮演着至关重要的角色,特别是在克服LLM的以下限制方面:

  1. 知识更新:LLM知识在预训练时固定,向量检索可实时补充最新信息
  2. 上下文窗口限制:通过检索最相关内容,最大化利用有限的上下文窗口
  3. 幻觉问题:检索到的事实内容可降低模型生成虚假信息的概率
  4. 领域专业性:检索行业专业文档,增强模型在特定领域的表现

典型应用:RAG架构

RAG(Retrieval-Augmented Generation)是结合向量检索和生成模型的经典架构,工作流程如下:

  1. 索引阶段

    • 将知识库文档分块(chunking)
    • 使用嵌入模型为每个块生成向量表示
    • 将向量存入向量数据库
  2. 查询阶段

    • 将用户问题转换为查询向量
    • 在向量数据库中检索最相关的文档块
    • 将检索到的内容与原始问题一起发送给LLM
    • LLM基于检索内容生成回答
python
# RAG简化实现示例
from sentence_transformers import SentenceTransformer
import numpy as np
import requests
import json

# 1. 准备向量模型
model = SentenceTransformer('paraphrase-MiniLM-L6-v2')

# 2. 示例知识库
documents = [
    "Python是一种高级编程语言,以易读性和简洁性著称。",
    "深度学习是机器学习的一个分支,使用多层神经网络进行学习。",
    "向量数据库专门设计用于存储和查询高维向量数据。",
    "大语言模型如GPT和DeepSeek具有强大的自然语言理解能力。"
]

# 3. 生成文档向量
doc_embeddings = model.encode(documents)

# 4. 简单的向量检索函数
def retrieve(query, top_k=2):
    # 编码查询
    query_embedding = model.encode([query])[0]
    
    # 计算相似度
    similarities = [np.dot(query_embedding, doc_embedding) 
                   for doc_embedding in doc_embeddings]
    
    # 找出最相似的文档
    top_indices = np.argsort(similarities)[-top_k:][::-1]
    return [documents[i] for i in top_indices]

# 5. 简化的LLM接口
def generate_answer(query, context):
    # 这里使用DeepSeek API (简化示例)
    prompt = f"""根据以下上下文回答问题。如果上下文中没有相关信息,请说"我不知道"。

上下文:
{' '.join(context)}

问题: {query}

回答:"""
    
    # 实际应用中,这里应该调用DeepSeek API
    print(f"发送到LLM的提示:\n{prompt}")
    
    # 模拟LLM返回
    return "这是基于检索内容的LLM生成回答。"

# 6. RAG流程
def rag(query):
    # 检索相关文档
    relevant_docs = retrieve(query)
    print(f"检索到的文档: {relevant_docs}")
    
    # 生成回答
    answer = generate_answer(query, relevant_docs)
    return answer

# 测试
query = "什么是大语言模型?"
answer = rag(query)
print(f"回答: {answer}")

小结

在本节中,我们学习了:

  1. 向量检索的基本概念和重要性
  2. 文本嵌入技术和向量表示基础
  3. 常用的向量相似度计算方法
  4. 主流向量索引算法及其特点
  5. 向量检索在大语言模型应用中的关键作用

向量检索是现代AI应用的基础设施,尤其在大语言模型应用中扮演着至关重要的角色。在接下来的章节中,我们将深入学习向量数据库的应用实践,以及如何构建高效的检索系统。

思考题

  1. 为什么余弦相似度在向量检索中比欧几里得距离更常用?
  2. HNSW算法相比传统树形结构算法有哪些优势?
  3. 在RAG架构中,文档分块(chunking)的大小和方式会如何影响最终的检索效果?
  4. 如何选择合适的嵌入模型来表示特定领域的文本内容?